package Core.plugin

import Core._
import spinal.core._
import spinal.lib._
import Core.ip._



case class PredictorConfig(predictorType : String = "GSHARE",
                           addressWidth : Int=32,
                           RAS_ENTRIES : Int=4,
                           BTB_ENTRIES : Int=4,
                           PHT_ENTRIES : Int=128
                          ){
    def PHT_address_width = log2Up(PHT_ENTRIES)
    def BTB_ENTRIES_WIDTH = log2Up(BTB_ENTRIES)
    def RAS_ENTRIES_WIDTH = log2Up(RAS_ENTRIES)
    def historyLen        = log2Up(PHT_ENTRIES)
}

class BPUPlugin(val p : PredictorConfig) extends Plugin[CPUSimple] {
    override def setup(pipeline: CPUSimple): Unit = {
        import LoongArch._
        import pipeline.config._
    }



    override def build(pipeline: CPUSimple): Unit = {
        import LoongArch._
        import pipeline._
        import pipeline.config._
        val predictor_config = BPUPlugin.this.p

        if(predictor_config.predictorType=="GSHARE"){
            val predictor = new gshare_predictor(predictor_config)
            predictor.predict_pc           := fetch.output(PREDICT_PC)
            predictor.predict_valid        := fetch.output(PREDICT_VALID)
            fetch.insert(BPU_BRANCH_TAKEN) := predictor.predict_taken
            fetch.insert(BPU_PC_NEXT)      := predictor.predict_pc_next
            predictor.train_valid          := decode.output(BRANCH_OR_JUMP)
            predictor.train_taken          := decode.output(BRANCH_TAKEN)
            predictor.train_mispredicted   := decode.output(REDIRECT_VALID)
            predictor.train_history        := decode.output(BRANCH_HISTORY)
            predictor.train_pc             := decode.output(PC)
            predictor.train_pc_next        := decode.output(REDIRECT_PC_NEXT)
            predictor.train_is_call        := decode.output(IS_CALL)
            predictor.train_is_return      := decode.output(IS_RETURN)
            predictor.train_is_jump        := decode.output(IS_JUMP)
        }

        else if(predictor_config.predictorType=="STATIC"){
            val predictor = new static_predictor(predictor_config)
            predictor.predict_pc           := decode.output(PC)
            predictor.predict_valid        := decode.output(PREDICT_VALID)
            predictor.predict_imm          := decode.output(FETCH_DEC_IMM)
            predictor.predict_jirl         := decode.output(FETCH_DEC_JIRL)
            predictor.predict_branch       := decode.output(FETCH_DEC_BRANCH)
            fetch.insert(BPU_BRANCH_TAKEN) := predictor.predict_taken
            fetch.insert(BPU_PC_NEXT)      := predictor.predict_pc_next
        }
    }
}
